import request from '@/util/axios';
import type { GenerateFileSha256Data } from './type';
import type { Res } from '@/api/types';
import CryptoJS from 'crypto-js';

// 统一管理接口
enum API {
  Download = '/api/file/download', // 下载文件
  Merge = '/api/file/merge', // 合并文件
  ChunkUpload = '/api/file/chunk_upload', // 分片上传
  Prepare = '/api/file/prepare' // 分片上传准备
}

/**
 * @method 文件上传预请求
 */
export function prepare(sha256: string) {
  return new Promise<Res<string>>((resolve) => {
    request.post(API.Prepare, { sha256 }).then((rs: any) => {
      resolve(rs);
    });
  });
}

/**
 * @method 文件分块上传
 */
export function chunkUpload(sha256: string, upload_id: string, file: any) {
  const formData = new FormData();
  formData.append('sha256', sha256);
  formData.append('upload_id', upload_id);
  formData.append('file', file);
  return new Promise<Res<string>>((resolve) => {
    request
      .post(API.ChunkUpload, formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
      .then((rs: any) => {
        resolve(rs);
      });
  });
}

/**
 * @method 文件合并
 */
export function merge(
  sha256: string,
  upload_id: string,
  chunks: string[],
  file_name: string,
  file_type: string
) {
  return new Promise<Res<string>>((resolve) => {
    request.post(API.Merge, { sha256, upload_id, chunks, file_name, file_type }).then((rs: any) => {
      resolve(rs);
    });
  });
}

/**
 * @method 文件下载(显示)
 */
export function download(file_info: string, file_type: string) {
  if (!file_info) {
    console.error('文件信息为空');
    return '';
  }
  return `${import.meta.env.VITE_APP_BASE_URL}${API.Download}?file_info=${file_info}&file_type=${file_type}`;
}

/**
 * @method 文件分块 分片计算文件的 sha256
 */
export async function generateFileSha256(
  file: File,
  chunkSize: number
): Promise<GenerateFileSha256Data> {
  let start = 0;
  let end = 0;
  const fileSize = file.size;

  const sha256Hash = CryptoJS.algo.SHA256.create();
  const chunkMap: Map<number, string> = new Map();
  const chunkData: Blob[] = [];

  let index = 0;
  while (start < fileSize) {
    end = start + chunkSize;
    if (end > fileSize) {
      end = fileSize;
    }

    const chunk: Blob = file.slice(start, end);

    chunkData.push(chunk);

    await new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = () => {
        try {
          const arrayBuffer = fileReader.result as ArrayBuffer;
          const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
          sha256Hash.update(wordArray);

          // 计算分片的 md5 值, 用于分片上传的数据,检查上传数据的正确性
          const chunkMD5 = CryptoJS.algo.MD5.create();
          chunkMD5.update(wordArray);
          chunkMap.set(index, chunkMD5.finalize().toString(CryptoJS.enc.Hex));
          resolve(null);
        } catch (error) {
          console.log('文件分片处理失败: ', error);
          reject(error);
        }
      };

      fileReader.onerror = (event) => {
        reject(new Error(`文件分片读取错误: ${(event.target as any).error}`));
      };

      fileReader.readAsArrayBuffer(chunk);
    });

    start = end;
    index = index + 1;
  }

  const result: GenerateFileSha256Data = {
    sha256: sha256Hash.finalize().toString(CryptoJS.enc.Hex),
    chunkMap: chunkMap,
    chunks: chunkData
  };

  return result;
}
